import { TypePaintBrush, TypePaintBrushLineDash, lineStyleType } from "../../typing";

export class PaintBrush {
    public ctx!: CanvasRenderingContext2D; // 画笔的上下文
    public width: number = 0; // 画笔层的宽度
    public height: number = 0; // 画笔层的高度
    public lineColor: string = '#000000'; // 画笔的颜色
    public lineWidth: number = 2; // 画笔的粗细
    public lineType: TypePaintBrushLineDash = "solid"; // 画笔的类型：实线 or 虚线

    public currentLineBeginPoint: [number, number] = [-1, -1] // 当前线段开始的点的坐标
    public currentLinePoints: [number, number][] = []; // 存放当前线段的每个点

    public type: TypePaintBrush = 'pen'; // 当前线段的类型：笔 or 橡皮
    public isDrawLine: boolean = true; // 是否允许画线

    constructor(public el: HTMLCanvasElement) {
        this.initCanvas();
    }
    // 画布的初始化
    initCanvas = () => {
        this.ctx = this.el.getContext("2d")!;
        const { width, height } = this.el.getBoundingClientRect();
        this.width = width;
        this.height = height;
        this.el.width = this.width;
        this.el.height = this.height;
        this.ctx.lineCap = 'round';
        this.setLineStyle({
            strokeStyle: this.lineColor,
            lineWidth: this.lineWidth,
            lineDash: this.lineType,
        })
        this.clearCanvas();
    }

    // 清空画布
    clearCanvas = (top = 0, left = 0, width = this.width, height = this.height) => this.ctx.clearRect(top, left, width, height);

    // 设置画笔的样式
    setLineStyle = (styleObject: lineStyleType, type: TypePaintBrush = this.type) => {
        this.type = type;
        // 设置线段的宽度
        if (styleObject.lineWidth) this.ctx.lineWidth = this.lineWidth = styleObject.lineWidth;
        // 设置线段的颜色
        if (styleObject.strokeStyle) this.ctx.strokeStyle = this.lineColor = styleObject.strokeStyle;
        // 设置线段的类型：实线 和 虚线
        if (styleObject.lineDash) {
            this.lineType = styleObject.lineDash;
            let dash: number[] = []
            if (this.lineType !== 'solid') {
                switch (this.lineWidth) {
                    case 1:
                    case 2:
                    case 3:
                    case 4:
                    case 5:
                    case 6:
                    case 7:
                    case 8:
                    case 9:
                    case 10:
                        dash = [4, 8];
                        break;
                }
            }
            this.ctx.setLineDash(dash);
        }
    }

    // 绑定 or 卸载 事件
    bindEvent = (isUninstall = false) => {
        if (isUninstall) {
            this.el.removeEventListener("mousedown", this.mouseDown)
        } else {
            this.el.addEventListener("mousedown", this.mouseDown)
        }
    }

    // 鼠标按下事件
    mouseDown = (downEvent: MouseEvent) => {
        if (!this.isDrawLine) {
            return;
        }
        this.currentLineBeginPoint[0] = downEvent.clientX;
        this.currentLineBeginPoint[1] = downEvent.clientY;
        this.currentLinePoints.push([downEvent.clientX, downEvent.clientY])

        this.el.addEventListener("mousemove", this.mouseMove);
    }

    // 鼠标移动事件
    mouseMove = (moveEvent: MouseEvent) => {
        this.currentLinePoints.push([moveEvent.clientX, moveEvent.clientY])
        this.ctx.beginPath();

        if (this.currentLinePoints.length > 2) {
            const lastTwoPoints = this.currentLinePoints.slice(-2);
            const controlPoint = lastTwoPoints[0];
            const endPoint: [number, number] = [(lastTwoPoints[0][0] + lastTwoPoints[1][0]) / 2, (lastTwoPoints[0][1] + lastTwoPoints[1][1]) / 2];
            this.drawLine(this.currentLineBeginPoint, controlPoint, endPoint);
            this.currentLineBeginPoint = [...endPoint];
        }
    }

    // 绘制平滑线段
    drawLine = (beginPoint: [number, number], controlPoint: [number, number], endPoint: [number, number]) => {
        if (this.type === 'pen' || this.type === 'fluorescence') {
            this.ctx.globalCompositeOperation = 'source-over';
        } else {
            this.ctx.globalCompositeOperation = 'destination-out';
        }
        if (this.type === 'fluorescence') {
            this.ctx.shadowColor = this.lineColor;
            this.ctx.shadowBlur = this.lineWidth * 2.5;
        } else {
            this.ctx.shadowColor = '';
            this.ctx.shadowBlur = 0;
        }
        this.ctx.moveTo(beginPoint[0], beginPoint[1]);
        this.ctx.quadraticCurveTo(controlPoint[0], controlPoint[1], endPoint[0], endPoint[1]);
        this.ctx.stroke();
        this.ctx.closePath();
    }
}